1   /*
2    * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package com.sun.java.swing.plaf.gtk;
27  
28  import java.awt.*;
29  import java.awt.image.*;
30  import java.util.HashMap;
31  import javax.swing.*;
32  import javax.swing.plaf.synth.*;
33  
34  import com.sun.java.swing.plaf.gtk.GTKConstants.ArrowType;
35  import com.sun.java.swing.plaf.gtk.GTKConstants.ExpanderStyle;
36  import com.sun.java.swing.plaf.gtk.GTKConstants.Orientation;
37  import com.sun.java.swing.plaf.gtk.GTKConstants.PositionType;
38  import com.sun.java.swing.plaf.gtk.GTKConstants.ShadowType;
39  import com.sun.java.swing.plaf.gtk.GTKConstants.TextDirection;
40  
41  import sun.awt.image.SunWritableRaster;
42  import sun.swing.ImageCache;
43  
44  /**
45   * GTKEngine delegates all painting job to native GTK libraries.
46   *
47   * Painting with GTKEngine looks like this:
48   * First, startPainting() is called. It prepares an offscreen buffer of the
49   *   required size.
50   * Then, any number of paintXXX() methods can be called. They effectively ignore
51   *   the Graphics parameter and draw to the offscreen buffer.
52   * Finally, finishPainting() should be called. It fills the data buffer passed
53   *   in with the image data.
54   *
55   * @author Josh Outwater
56   */
57  class GTKEngine {
58  
59      final static GTKEngine INSTANCE = new GTKEngine();
60  
61      /** Size of the image cache */
62      private static final int CACHE_SIZE = 50;
63  
64      /** This enum mirrors that in gtk2_interface.h */
65      static enum WidgetType {
66          BUTTON, CHECK_BOX, CHECK_BOX_MENU_ITEM, COLOR_CHOOSER,
67          COMBO_BOX, COMBO_BOX_ARROW_BUTTON, COMBO_BOX_TEXT_FIELD,
68          DESKTOP_ICON, DESKTOP_PANE, EDITOR_PANE, FORMATTED_TEXT_FIELD,
69          HANDLE_BOX, HPROGRESS_BAR,
70          HSCROLL_BAR, HSCROLL_BAR_BUTTON_LEFT, HSCROLL_BAR_BUTTON_RIGHT,
71          HSCROLL_BAR_TRACK, HSCROLL_BAR_THUMB,
72          HSEPARATOR, HSLIDER, HSLIDER_TRACK, HSLIDER_THUMB, HSPLIT_PANE_DIVIDER,
73          INTERNAL_FRAME, INTERNAL_FRAME_TITLE_PANE, IMAGE, LABEL, LIST, MENU,
74          MENU_BAR, MENU_ITEM, MENU_ITEM_ACCELERATOR, OPTION_PANE, PANEL,
75          PASSWORD_FIELD, POPUP_MENU, POPUP_MENU_SEPARATOR,
76          RADIO_BUTTON, RADIO_BUTTON_MENU_ITEM, ROOT_PANE, SCROLL_PANE,
77          SPINNER, SPINNER_ARROW_BUTTON, SPINNER_TEXT_FIELD,
78          SPLIT_PANE, TABBED_PANE, TABBED_PANE_TAB_AREA, TABBED_PANE_CONTENT,
79          TABBED_PANE_TAB, TABLE, TABLE_HEADER, TEXT_AREA, TEXT_FIELD, TEXT_PANE,
80          TITLED_BORDER,
81          TOGGLE_BUTTON, TOOL_BAR, TOOL_BAR_DRAG_WINDOW, TOOL_BAR_SEPARATOR,
82          TOOL_TIP, TREE, TREE_CELL, VIEWPORT, VPROGRESS_BAR,
83          VSCROLL_BAR, VSCROLL_BAR_BUTTON_UP, VSCROLL_BAR_BUTTON_DOWN,
84          VSCROLL_BAR_TRACK, VSCROLL_BAR_THUMB,
85          VSEPARATOR, VSLIDER, VSLIDER_TRACK, VSLIDER_THUMB,
86          VSPLIT_PANE_DIVIDER
87      }
88  
89      /**
90       * Representation of GtkSettings properties.
91       * When we need more settings we can add them here and
92       * to all implementations of getGTKSetting().
93       */
94      static enum Settings {
95          GTK_FONT_NAME,
96          GTK_ICON_SIZES
97      }
98  
99      /* Custom regions are needed for representing regions that don't exist
100      * in the original Region class.
101      */
102     static class CustomRegion extends Region {
103         /*
104          * TITLED_BORDER Region is mapped to GtkFrame class which can draw
105          * titled borders around components.
106          */
107         static Region TITLED_BORDER = new CustomRegion("TitledBorder");
108 
109         private CustomRegion(String name) {
110             super(name, null, false);
111         }
112     }
113 
114 
115     private static HashMap<Region, Object> regionToWidgetTypeMap;
116     private ImageCache cache = new ImageCache(CACHE_SIZE);
117     private int x0, y0, w0, h0;
118     private Graphics graphics;
119     private Object[] cacheArgs;
120 
121     private native void native_paint_arrow(
122             int widgetType, int state, int shadowType, String detail,
123             int x, int y, int width, int height, int arrowType);
124     private native void native_paint_box(
125             int widgetType, int state, int shadowType, String detail,
126             int x, int y, int width, int height, int synthState, int dir);
127     private native void native_paint_box_gap(
128             int widgetType, int state, int shadowType, String detail,
129             int x, int y, int width, int height,
130             int gapSide, int gapX, int gapWidth);
131     private native void native_paint_check(
132             int widgetType, int synthState, String detail,
133             int x, int y, int width, int height);
134     private native void native_paint_expander(
135             int widgetType, int state, String detail,
136             int x, int y, int width, int height, int expanderStyle);
137     private native void native_paint_extension(
138             int widgetType, int state, int shadowType, String detail,
139             int x, int y, int width, int height, int placement);
140     private native void native_paint_flat_box(
141             int widgetType, int state, int shadowType, String detail,
142             int x, int y, int width, int height, boolean hasFocus);
143     private native void native_paint_focus(
144             int widgetType, int state, String detail,
145             int x, int y, int width, int height);
146     private native void native_paint_handle(
147             int widgetType, int state, int shadowType, String detail,
148             int x, int y, int width, int height, int orientation);
149     private native void native_paint_hline(
150             int widgetType, int state, String detail,
151             int x, int y, int width, int height);
152     private native void native_paint_option(
153             int widgetType, int synthState, String detail,
154             int x, int y, int width, int height);
155     private native void native_paint_shadow(
156             int widgetType, int state, int shadowType, String detail,
157             int x, int y, int width, int height, int synthState, int dir);
158     private native void native_paint_slider(
159             int widgetType, int state, int shadowType, String detail,
160             int x, int y, int width, int height, int orientation);
161     private native void native_paint_vline(
162             int widgetType, int state, String detail,
163             int x, int y, int width, int height);
164     private native void native_paint_background(
165             int widgetType, int state, int x, int y, int width, int height);
166     private native Object native_get_gtk_setting(int property);
167     private native void nativeSetRangeValue(int widgetType, double value,
168                                             double min, double max,
169                                             double visible);
170 
171     private native void nativeStartPainting(int w, int h);
172     private native int nativeFinishPainting(int[] buffer, int width, int height);
173     private native void native_switch_theme();
174 
175     static {
176         // Make sure the awt toolkit is loaded so we have access to native
177         // methods.
178         Toolkit.getDefaultToolkit();
179 
180         // Initialize regionToWidgetTypeMap
181         regionToWidgetTypeMap = new HashMap<Region, Object>(50);
182         regionToWidgetTypeMap.put(Region.ARROW_BUTTON, new WidgetType[] {
183             WidgetType.SPINNER_ARROW_BUTTON,
184             WidgetType.COMBO_BOX_ARROW_BUTTON,
185             WidgetType.HSCROLL_BAR_BUTTON_LEFT,
186             WidgetType.HSCROLL_BAR_BUTTON_RIGHT,
187             WidgetType.VSCROLL_BAR_BUTTON_UP,
188             WidgetType.VSCROLL_BAR_BUTTON_DOWN});
189         regionToWidgetTypeMap.put(Region.BUTTON, WidgetType.BUTTON);
190         regionToWidgetTypeMap.put(Region.CHECK_BOX, WidgetType.CHECK_BOX);
191         regionToWidgetTypeMap.put(Region.CHECK_BOX_MENU_ITEM,
192                                   WidgetType.CHECK_BOX_MENU_ITEM);
193         regionToWidgetTypeMap.put(Region.COLOR_CHOOSER, WidgetType.COLOR_CHOOSER);
194         regionToWidgetTypeMap.put(Region.FILE_CHOOSER, WidgetType.OPTION_PANE);
195         regionToWidgetTypeMap.put(Region.COMBO_BOX, WidgetType.COMBO_BOX);
196         regionToWidgetTypeMap.put(Region.DESKTOP_ICON, WidgetType.DESKTOP_ICON);
197         regionToWidgetTypeMap.put(Region.DESKTOP_PANE, WidgetType.DESKTOP_PANE);
198         regionToWidgetTypeMap.put(Region.EDITOR_PANE, WidgetType.EDITOR_PANE);
199         regionToWidgetTypeMap.put(Region.FORMATTED_TEXT_FIELD, new WidgetType[] {
200             WidgetType.FORMATTED_TEXT_FIELD, WidgetType.SPINNER_TEXT_FIELD});
201         regionToWidgetTypeMap.put(GTKRegion.HANDLE_BOX, WidgetType.HANDLE_BOX);
202         regionToWidgetTypeMap.put(Region.INTERNAL_FRAME,
203                                   WidgetType.INTERNAL_FRAME);
204         regionToWidgetTypeMap.put(Region.INTERNAL_FRAME_TITLE_PANE,
205                                   WidgetType.INTERNAL_FRAME_TITLE_PANE);
206         regionToWidgetTypeMap.put(Region.LABEL, new WidgetType[] {
207             WidgetType.LABEL, WidgetType.COMBO_BOX_TEXT_FIELD});
208         regionToWidgetTypeMap.put(Region.LIST, WidgetType.LIST);
209         regionToWidgetTypeMap.put(Region.MENU, WidgetType.MENU);
210         regionToWidgetTypeMap.put(Region.MENU_BAR, WidgetType.MENU_BAR);
211         regionToWidgetTypeMap.put(Region.MENU_ITEM, WidgetType.MENU_ITEM);
212         regionToWidgetTypeMap.put(Region.MENU_ITEM_ACCELERATOR,
213                                   WidgetType.MENU_ITEM_ACCELERATOR);
214         regionToWidgetTypeMap.put(Region.OPTION_PANE, WidgetType.OPTION_PANE);
215         regionToWidgetTypeMap.put(Region.PANEL, WidgetType.PANEL);
216         regionToWidgetTypeMap.put(Region.PASSWORD_FIELD,
217                                   WidgetType.PASSWORD_FIELD);
218         regionToWidgetTypeMap.put(Region.POPUP_MENU, WidgetType.POPUP_MENU);
219         regionToWidgetTypeMap.put(Region.POPUP_MENU_SEPARATOR,
220                                   WidgetType.POPUP_MENU_SEPARATOR);
221         regionToWidgetTypeMap.put(Region.PROGRESS_BAR, new WidgetType[] {
222             WidgetType.HPROGRESS_BAR, WidgetType.VPROGRESS_BAR});
223         regionToWidgetTypeMap.put(Region.RADIO_BUTTON, WidgetType.RADIO_BUTTON);
224         regionToWidgetTypeMap.put(Region.RADIO_BUTTON_MENU_ITEM,
225                                   WidgetType.RADIO_BUTTON_MENU_ITEM);
226         regionToWidgetTypeMap.put(Region.ROOT_PANE, WidgetType.ROOT_PANE);
227         regionToWidgetTypeMap.put(Region.SCROLL_BAR, new WidgetType[] {
228             WidgetType.HSCROLL_BAR, WidgetType.VSCROLL_BAR});
229         regionToWidgetTypeMap.put(Region.SCROLL_BAR_THUMB, new WidgetType[] {
230             WidgetType.HSCROLL_BAR_THUMB, WidgetType.VSCROLL_BAR_THUMB});
231         regionToWidgetTypeMap.put(Region.SCROLL_BAR_TRACK, new WidgetType[] {
232             WidgetType.HSCROLL_BAR_TRACK, WidgetType.VSCROLL_BAR_TRACK});
233         regionToWidgetTypeMap.put(Region.SCROLL_PANE, WidgetType.SCROLL_PANE);
234         regionToWidgetTypeMap.put(Region.SEPARATOR, new WidgetType[] {
235             WidgetType.HSEPARATOR, WidgetType.VSEPARATOR});
236         regionToWidgetTypeMap.put(Region.SLIDER, new WidgetType[] {
237             WidgetType.HSLIDER, WidgetType.VSLIDER});
238         regionToWidgetTypeMap.put(Region.SLIDER_THUMB, new WidgetType[] {
239             WidgetType.HSLIDER_THUMB, WidgetType.VSLIDER_THUMB});
240         regionToWidgetTypeMap.put(Region.SLIDER_TRACK, new WidgetType[] {
241             WidgetType.HSLIDER_TRACK, WidgetType.VSLIDER_TRACK});
242         regionToWidgetTypeMap.put(Region.SPINNER, WidgetType.SPINNER);
243         regionToWidgetTypeMap.put(Region.SPLIT_PANE, WidgetType.SPLIT_PANE);
244         regionToWidgetTypeMap.put(Region.SPLIT_PANE_DIVIDER, new WidgetType[] {
245             WidgetType.HSPLIT_PANE_DIVIDER, WidgetType.VSPLIT_PANE_DIVIDER});
246         regionToWidgetTypeMap.put(Region.TABBED_PANE, WidgetType.TABBED_PANE);
247         regionToWidgetTypeMap.put(Region.TABBED_PANE_CONTENT,
248                                   WidgetType.TABBED_PANE_CONTENT);
249         regionToWidgetTypeMap.put(Region.TABBED_PANE_TAB,
250                                   WidgetType.TABBED_PANE_TAB);
251         regionToWidgetTypeMap.put(Region.TABBED_PANE_TAB_AREA,
252                                   WidgetType.TABBED_PANE_TAB_AREA);
253         regionToWidgetTypeMap.put(Region.TABLE, WidgetType.TABLE);
254         regionToWidgetTypeMap.put(Region.TABLE_HEADER, WidgetType.TABLE_HEADER);
255         regionToWidgetTypeMap.put(Region.TEXT_AREA, WidgetType.TEXT_AREA);
256         regionToWidgetTypeMap.put(Region.TEXT_FIELD, new WidgetType[] {
257             WidgetType.TEXT_FIELD, WidgetType.COMBO_BOX_TEXT_FIELD});
258         regionToWidgetTypeMap.put(Region.TEXT_PANE, WidgetType.TEXT_PANE);
259         regionToWidgetTypeMap.put(CustomRegion.TITLED_BORDER, WidgetType.TITLED_BORDER);
260         regionToWidgetTypeMap.put(Region.TOGGLE_BUTTON, WidgetType.TOGGLE_BUTTON);
261         regionToWidgetTypeMap.put(Region.TOOL_BAR, WidgetType.TOOL_BAR);
262         regionToWidgetTypeMap.put(Region.TOOL_BAR_CONTENT, WidgetType.TOOL_BAR);
263         regionToWidgetTypeMap.put(Region.TOOL_BAR_DRAG_WINDOW,
264                                   WidgetType.TOOL_BAR_DRAG_WINDOW);
265         regionToWidgetTypeMap.put(Region.TOOL_BAR_SEPARATOR,
266                                   WidgetType.TOOL_BAR_SEPARATOR);
267         regionToWidgetTypeMap.put(Region.TOOL_TIP, WidgetType.TOOL_TIP);
268         regionToWidgetTypeMap.put(Region.TREE, WidgetType.TREE);
269         regionToWidgetTypeMap.put(Region.TREE_CELL, WidgetType.TREE_CELL);
270         regionToWidgetTypeMap.put(Region.VIEWPORT, WidgetType.VIEWPORT);
271     }
272 
273     /** Translate Region and JComponent into WidgetType ordinals */
274     static WidgetType getWidgetType(JComponent c, Region id) {
275         Object value = regionToWidgetTypeMap.get(id);
276 
277         if (value instanceof WidgetType) {
278             return (WidgetType)value;
279         }
280 
281         WidgetType[] widgets = (WidgetType[])value;
282         if (c == null ) {
283             return widgets[0];
284         }
285 
286         if (c instanceof JScrollBar) {
287             return (((JScrollBar)c).getOrientation() == JScrollBar.HORIZONTAL) ?
288                 widgets[0] : widgets[1];
289         } else if (c instanceof JSeparator) {
290             JSeparator separator = (JSeparator)c;
291 
292             /* We should return correrct WidgetType if the seperator is inserted
293              * in Menu/PopupMenu/ToolBar. BugID: 6465603
294              */
295             if (separator.getParent() instanceof JPopupMenu) {
296                 return WidgetType.POPUP_MENU_SEPARATOR;
297             } else if (separator.getParent() instanceof JToolBar) {
298                 return WidgetType.TOOL_BAR_SEPARATOR;
299             }
300 
301             return (separator.getOrientation() == JSeparator.HORIZONTAL) ?
302                 widgets[0] : widgets[1];
303         } else if (c instanceof JSlider) {
304             return (((JSlider)c).getOrientation() == JSlider.HORIZONTAL) ?
305                 widgets[0] : widgets[1];
306         } else if (c instanceof JProgressBar) {
307             return (((JProgressBar)c).getOrientation() == JProgressBar.HORIZONTAL) ?
308                 widgets[0] : widgets[1];
309         } else if (c instanceof JSplitPane) {
310             return (((JSplitPane)c).getOrientation() == JSplitPane.HORIZONTAL_SPLIT) ?
311                 widgets[1] : widgets[0];
312         } else if (id == Region.LABEL) {
313             /*
314              * For all ListCellRenderers we will use COMBO_BOX_TEXT_FIELD widget
315              * type because we can get correct insets. List items however won't be
316              * drawn as a text entry (see GTKPainter.paintLabelBackground).
317              */
318             if (c instanceof ListCellRenderer) {
319                 return widgets[1];
320             } else {
321                 return widgets[0];
322             }
323         } else if (id == Region.TEXT_FIELD) {
324             String name = c.getName();
325             if (name != null && name.startsWith("ComboBox")) {
326                 return widgets[1];
327             } else {
328                 return widgets[0];
329             }
330         } else if (id == Region.FORMATTED_TEXT_FIELD) {
331             String name = c.getName();
332             if (name != null && name.startsWith("Spinner")) {
333                 return widgets[1];
334             } else {
335                 return widgets[0];
336             }
337         } else if (id == Region.ARROW_BUTTON) {
338             if (c.getParent() instanceof JScrollBar) {
339                 Integer prop = (Integer)
340                     c.getClientProperty("__arrow_direction__");
341                 int dir = (prop != null) ?
342                     prop.intValue() : SwingConstants.WEST;
343                 switch (dir) {
344                 case SwingConstants.WEST:
345                     return WidgetType.HSCROLL_BAR_BUTTON_LEFT;
346                 case SwingConstants.EAST:
347                     return WidgetType.HSCROLL_BAR_BUTTON_RIGHT;
348                 case SwingConstants.NORTH:
349                     return WidgetType.VSCROLL_BAR_BUTTON_UP;
350                 case SwingConstants.SOUTH:
351                     return WidgetType.VSCROLL_BAR_BUTTON_DOWN;
352                 default:
353                     return null;
354                 }
355             } else if (c.getParent() instanceof JComboBox) {
356                 return WidgetType.COMBO_BOX_ARROW_BUTTON;
357             } else {
358                 return WidgetType.SPINNER_ARROW_BUTTON;
359             }
360         }
361 
362         return null;
363     }
364 
365     private static int getTextDirection(SynthContext context) {
366         TextDirection dir = TextDirection.NONE;
367         JComponent comp = context.getComponent();
368         if (comp != null) {
369             ComponentOrientation co = comp.getComponentOrientation();
370             if (co != null) {
371                 dir = co.isLeftToRight() ?
372                     TextDirection.LTR : TextDirection.RTL;
373             }
374         }
375         return dir.ordinal();
376     }
377 
378     public void paintArrow(Graphics g, SynthContext context,
379             Region id, int state, ShadowType shadowType, ArrowType direction,
380             String detail, int x, int y, int w, int h) {
381 
382         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
383         int widget = getWidgetType(context.getComponent(), id).ordinal();
384         native_paint_arrow(widget, state, shadowType.ordinal(),
385                 detail, x - x0, y - y0, w, h, direction.ordinal());
386     }
387 
388     public void paintBox(Graphics g, SynthContext context,
389             Region id, int state, ShadowType shadowType,
390             String detail, int x, int y, int w, int h) {
391 
392         int gtkState =
393             GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
394         int synthState = context.getComponentState();
395         int dir = getTextDirection(context);
396         int widget = getWidgetType(context.getComponent(), id).ordinal();
397         native_paint_box(widget, gtkState, shadowType.ordinal(),
398                          detail, x - x0, y - y0, w, h, synthState, dir);
399     }
400 
401     public void paintBoxGap(Graphics g, SynthContext context,
402             Region id, int state, ShadowType shadowType,
403             String detail, int x, int y, int w, int h,
404             PositionType boxGapType, int tabBegin, int size) {
405 
406         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
407         int widget = getWidgetType(context.getComponent(), id).ordinal();
408         native_paint_box_gap(widget, state, shadowType.ordinal(), detail,
409                 x - x0, y - y0, w, h, boxGapType.ordinal(), tabBegin, size);
410     }
411 
412     public void paintCheck(Graphics g, SynthContext context,
413             Region id, String detail, int x, int y, int w, int h) {
414 
415         int synthState = context.getComponentState();
416         int widget = getWidgetType(context.getComponent(), id).ordinal();
417         native_paint_check(widget, synthState, detail, x - x0, y - y0, w, h);
418     }
419 
420     public void paintExpander(Graphics g, SynthContext context,
421             Region id, int state, ExpanderStyle expanderStyle, String detail,
422             int x, int y, int w, int h) {
423 
424         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
425         int widget = getWidgetType(context.getComponent(), id).ordinal();
426         native_paint_expander(widget, state, detail, x - x0, y - y0, w, h,
427                               expanderStyle.ordinal());
428     }
429 
430     public void paintExtension(Graphics g, SynthContext context,
431             Region id, int state, ShadowType shadowType, String detail,
432             int x, int y, int w, int h, PositionType placement, int tabIndex) {
433 
434         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
435         int widget = getWidgetType(context.getComponent(), id).ordinal();
436         native_paint_extension(widget, state, shadowType.ordinal(), detail,
437                                x - x0, y - y0, w, h, placement.ordinal());
438     }
439 
440     public void paintFlatBox(Graphics g, SynthContext context,
441             Region id, int state, ShadowType shadowType, String detail,
442             int x, int y, int w, int h, ColorType colorType) {
443 
444         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
445         int widget = getWidgetType(context.getComponent(), id).ordinal();
446         native_paint_flat_box(widget, state, shadowType.ordinal(), detail,
447                               x - x0, y - y0, w, h,
448                               context.getComponent().hasFocus());
449     }
450 
451     public void paintFocus(Graphics g, SynthContext context,
452             Region id, int state, String detail, int x, int y, int w, int h) {
453 
454         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
455         int widget = getWidgetType(context.getComponent(), id).ordinal();
456         native_paint_focus(widget, state, detail, x - x0, y - y0, w, h);
457     }
458 
459     public void paintHandle(Graphics g, SynthContext context,
460             Region id, int state, ShadowType shadowType, String detail,
461             int x, int y, int w, int h, Orientation orientation) {
462 
463         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
464         int widget = getWidgetType(context.getComponent(), id).ordinal();
465         native_paint_handle(widget, state, shadowType.ordinal(), detail,
466                             x - x0, y - y0, w, h, orientation.ordinal());
467     }
468 
469     public void paintHline(Graphics g, SynthContext context,
470             Region id, int state, String detail, int x, int y, int w, int h) {
471 
472         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
473         int widget = getWidgetType(context.getComponent(), id).ordinal();
474         native_paint_hline(widget, state, detail, x - x0, y - y0, w, h);
475     }
476 
477     public void paintOption(Graphics g, SynthContext context,
478             Region id, String detail, int x, int y, int w, int h) {
479 
480         int synthState = context.getComponentState();
481         int widget = getWidgetType(context.getComponent(), id).ordinal();
482         native_paint_option(widget, synthState, detail, x - x0, y - y0, w, h);
483     }
484 
485     public void paintShadow(Graphics g, SynthContext context,
486             Region id, int state, ShadowType shadowType, String detail,
487             int x, int y, int w, int h) {
488 
489         int gtkState =
490             GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
491         int synthState = context.getComponentState();
492         int dir = getTextDirection(context);
493         int widget = getWidgetType(context.getComponent(), id).ordinal();
494         native_paint_shadow(widget, gtkState, shadowType.ordinal(), detail,
495                             x - x0, y - y0, w, h, synthState, dir);
496     }
497 
498     public void paintSlider(Graphics g, SynthContext context,
499             Region id, int state, ShadowType shadowType, String detail,
500             int x, int y, int w, int h, Orientation orientation) {
501 
502         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
503         int widget = getWidgetType(context.getComponent(), id).ordinal();
504         native_paint_slider(widget, state, shadowType.ordinal(), detail,
505                             x - x0, y - y0, w, h, orientation.ordinal());
506     }
507 
508     public void paintVline(Graphics g, SynthContext context,
509             Region id, int state, String detail, int x, int y, int w, int h) {
510 
511         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
512         int widget = getWidgetType(context.getComponent(), id).ordinal();
513         native_paint_vline(widget, state, detail, x - x0, y - y0, w, h);
514     }
515 
516     public void paintBackground(Graphics g, SynthContext context,
517             Region id, int state, Color color, int x, int y, int w, int h) {
518 
519         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
520         int widget = getWidgetType(context.getComponent(), id).ordinal();
521         native_paint_background(widget, state, x - x0, y - y0, w, h);
522     }
523 
524     private final static ColorModel[] COLOR_MODELS = {
525         // Transparency.OPAQUE
526         new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000),
527         // Transparency.BITMASK
528         new DirectColorModel(25, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x01000000),
529         // Transparency.TRANSLUCENT
530         ColorModel.getRGBdefault(),
531     };
532 
533     private final static int[][] BAND_OFFSETS = {
534         { 0x00ff0000, 0x0000ff00, 0x000000ff },             // OPAQUE
535         { 0x00ff0000, 0x0000ff00, 0x000000ff, 0x01000000 }, // BITMASK
536         { 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }  // TRANSLUCENT
537     };
538 
539 
540     /**
541      * Paint a cached image identified by its size and a set of additional
542      * arguments, if there's one.
543      *
544      * @return true if a cached image has been painted, false otherwise
545      */
546     public boolean paintCachedImage(Graphics g,
547             int x, int y, int w, int h, Object... args) {
548         if (w <= 0 || h <= 0) {
549             return true;
550         }
551 
552         // look for cached image
553         Image img = cache.getImage(getClass(), null, w, h, args);
554         if (img != null) {
555             g.drawImage(img, x, y, null);
556             return true;
557         }
558         return false;
559     }
560 
561     /*
562      * Allocate a native offscreen buffer of the specified size.
563      */
564     public void startPainting(Graphics g,
565             int x, int y, int w, int h, Object... args) {
566         nativeStartPainting(w, h);
567         x0 = x;
568         y0 = y;
569         w0 = w;
570         h0 = h;
571         graphics = g;
572         cacheArgs = args;
573     }
574 
575     /**
576      * Convenience method that delegates to finishPainting() with
577      * caching enabled.
578      */
579     public void finishPainting() {
580         finishPainting(true);
581     }
582 
583     /**
584      * Called to indicate that painting is finished. We create a new
585      * BufferedImage from the offscreen buffer, (optionally) cache it,
586      * and paint it.
587      */
588     public void finishPainting(boolean useCache) {
589         DataBufferInt dataBuffer = new DataBufferInt(w0 * h0);
590         // Note that stealData() requires a markDirty() afterwards
591         // since we modify the data in it.
592         int transparency =
593             nativeFinishPainting(SunWritableRaster.stealData(dataBuffer, 0),
594                                  w0, h0);
595         SunWritableRaster.markDirty(dataBuffer);
596 
597         int[] bands = BAND_OFFSETS[transparency - 1];
598         WritableRaster raster = Raster.createPackedRaster(
599                 dataBuffer, w0, h0, w0, bands, null);
600 
601         ColorModel cm = COLOR_MODELS[transparency - 1];
602         Image img = new BufferedImage(cm, raster, false, null);
603         if (useCache) {
604             cache.setImage(getClass(), null, w0, h0, cacheArgs, img);
605         }
606         graphics.drawImage(img, x0, y0, null);
607     }
608 
609     /**
610      * Notify native layer of theme change, and flush cache
611      */
612     public void themeChanged() {
613         synchronized(sun.awt.UNIXToolkit.GTK_LOCK) {
614             native_switch_theme();
615         }
616         cache.flush();
617     }
618 
619     /* GtkSettings enum mirrors that in gtk2_interface.h */
620     public Object getSetting(Settings property) {
621         synchronized(sun.awt.UNIXToolkit.GTK_LOCK) {
622             return native_get_gtk_setting(property.ordinal());
623         }
624     }
625 
626     /**
627      * Sets up the GtkAdjustment values for the native GtkRange widget
628      * associated with the given region (e.g. SLIDER, SCROLL_BAR).
629      */
630     void setRangeValue(SynthContext context, Region id,
631                        double value, double min, double max, double visible) {
632         int widget = getWidgetType(context.getComponent(), id).ordinal();
633         nativeSetRangeValue(widget, value, min, max, visible);
634     }
635 }